using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using T.FAS.Runtime.ScheduleJob.SPI;
using T.ServiceComponent.DAC.Service;
using AppContext = T.ServiceComponent.Session.Service.AppContext;

namespace T.FAS.Runtime.ScheduleJob.Dao
{
    public class InternationalDaoTools
    {
        public static bool IsDebug { get; set; } = false;

        /// <summary>
        /// 将当前语言区域的语言列，赋值到主语言列，例如将Name_Lang2 => Name
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="metadatas"></param>
        /// <param name="dt"></param>
        /// <param name="daoService"></param>
        public static void FillInternationalFields<T>(List<T> metadatas, DataTable dt, DaoService<T> daoService)
        {
            if (metadatas == null || metadatas.Count == 0 || dt == null || dt.Rows.Count == 0) return;
            if (daoService == null || IsMainLanguage()) return;
            var suffix = GetCurLocaleRepositoryCode();
            if (suffix == null) return;
            foreach (DataRow dataRow in dt.Rows)
            {
                var id = dataRow[daoService.IDColumnName]?.ToString();
                var meta = metadatas.FirstOrDefault(m => GetValue(m, daoService.IDColumnName)?.ToString() == id);
                if (meta != null)
                {
                    var i18Ns = GetInternationalFields<T>();
                    foreach (var i18NPropOrFieldName in i18Ns)
                    {
                        string i18NFieldName = i18NPropOrFieldName + "_" + suffix;
                        //兼容物理表不存在多语言字段的情况
                        if (dt.Columns.Contains(i18NFieldName))
                            SetValue(meta, i18NPropOrFieldName, dataRow[i18NFieldName]);
                    }
                }
            }
        }

        /// <summary>
        /// 返回Lang1
        /// </summary>
        /// <returns></returns>
        private static string GetCurLocaleRepositoryCode()
        {
            string curLocale = "zh-CN";
            if (IsDebug) curLocale = "en-US";
            try
            {
                //curLocale = AppContext.Current.Session[internationalSessionKey]?.ToString();
                if (AppContext.Current.Language != null)
                {
                    curLocale = AppContext.Current.Language.ID;
                }
                else
                {
                    curLocale = AppContext.Current.Session["t_locale"]?.ToString();
                }
            }
            catch
            {
            }
            foreach (var pair in InternationalDataTools.LanguageMapping)
            {
                if (pair.Value == curLocale)
                {
                    return pair.Key;
                }
            }
            return null;
        }

        private static bool IsMainLanguage()
        {
            if (IsDebug) return false;
            return AppContext.Current.Language == null || AppContext.Current.Language.IsMainLanguage;
        }

        private static void SetValue<T>(T obj, string fieldName, object value)
        {
            var type = typeof(T);
            var field = type.GetField(fieldName);
            if (field == null)
            {
                var prop = type.GetProperty(fieldName);
                if (prop == null)
                    throw new Exception($"type:{type.Name} doesn't have {fieldName} prop or field");
                else if (value == DBNull.Value)
                    prop.SetValue(obj, null);
                else
                    prop.SetValue(obj, value);
            }
            else
            {
                field.SetValue(obj, value);
            }
        }

        private static object GetValue<T>(T obj, string fieldName)
        {
            var type = typeof(T);
            var field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
            object value;
            if (field == null)
            {
                var prop = type.GetProperty(fieldName, BindingFlags.Public | BindingFlags.Instance);
                if (prop == null)
                    throw new Exception($"type:{type.Name} doesn't have {fieldName} prop or field");
                else
                    value = prop.GetValue(obj);
            }
            else
            {
                value = field.GetValue(obj);
            }
            return value;
        }

        private static IEnumerable<string> GetInternationalFields<T>()
        {
            Type type = typeof(T);
            //只取当前类的属性以及字段DeclaredOnly;
            var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.Public).Where(field => !field.Name.EndsWith("k__BackingField"));

            var i18NProps = propertyInfos.Where(p => p.GetCustomAttribute<InternationalAttribute>() != null)?.Select(p => p.Name) ?? new List<string>();
            var i18NFields = fieldInfos.Where(p => p.GetCustomAttribute<InternationalAttribute>() != null)?.Select(p => p.Name) ?? new List<string>();

            return i18NProps.Concat(i18NFields);
        }

        #region 暂时没用
        /// <summary>
        /// 暂不考虑多语言录入，可以通过低代码的方式处理
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="instances"></param>
        /// <param name="daoService"></param>
        /// <exception cref="Exception"></exception>
        private void ProcessInternationalFields<T>(List<T> instances, DaoService<T> daoService)
        {

        }

        private static string GetUpdateFieldSQL(string fieldName, string suffix)
        {
            return $"{fieldName}_{suffix}=@{fieldName}_{suffix}";
        }

        private static string GetUpdateParmeterSQL(string fieldName, string suffix)
        {
            return $"@{fieldName}_{suffix}";
        }

        #endregion

        public static List<string> GenerateI18NFields<T>(DaoService<T> daoService, int type = 0)
        {
            string dml = "alter table {0} add {1} varchar(512); ";
            //string updateSQL = "update {0} set {1}=Concat('{3}',{2}); ";
            string updateSQL = "update {0} set {1}={2}; ";
            List<string> sqls = new List<string>();
            var i18NFields = GetInternationalFields<T>();
            if (i18NFields != null)
            {
                foreach (var i18NField in i18NFields)
                {
                    foreach (var lang in InternationalDataTools.DefaultParalanguage)
                    {
                        string addColSQL = string.Format(dml, daoService.TableName, i18NField + "_" + lang);
                        string updateFieldSQL = string.Format(updateSQL, daoService.TableName, i18NField + "_" + lang, i18NField, lang);
                        if (type != 0)
                        {
                            updateFieldSQL = addColSQL + updateFieldSQL;
                        }

                        sqls.Add(updateFieldSQL);
                    }
                }
            }
            return sqls;
        }
    }
}